home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / SPIM Folder / Sources / spim-uti.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-10  |  10.9 KB  |  498 lines  |  [TEXT/ttxt]

  1. /* SPIM S20 MIPS simulator.
  2.    Misc. routines for SPIM.
  3.    Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
  4.  
  5.    SPIM is free software; you can redistribute it and/or modify it
  6.    under the terms of the GNU General Public License as published by the
  7.    Free Software Foundation; either version 1, or (at your option) any
  8.    later version.
  9.  
  10.    SPIM is distributed in the hope that it will be useful, but WITHOUT
  11.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13.    for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with GNU CC; see the file COPYING.  If not, write to James R.
  17.    Larus, Computer Sciences Department, University of Wisconsin--Madison,
  18.    1210 West Dayton Street, Madison, WI 53706, USA or to the Free
  19.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21.  
  22. /* $Header: /var/home/cs354/.spim/RCS/spim-utils.c,v 1.5 1992/10/12 11:38:15 cs354 Exp $
  23. */
  24.  
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include "spim.h"
  29. #include "inst.h"
  30. #include "mem.h"
  31. #include "reg.h"
  32. #include "sym_tbl.h"
  33. #ifdef WIN32
  34. #include "version.h"
  35. #define DEFAULT_TRAP_HANDLER "traphand.sim"
  36. #include "y_tab.h"
  37. #else
  38. #ifdef MACINTOSH
  39. #include "version.h"
  40. #define DEFAULT_TRAP_HANDLER "trap.handler"
  41. #include "y_tab.h"
  42. #else
  43. #include "y.tab.h"
  44. #endif
  45. #endif
  46. #include "data.h"
  47.  
  48.  
  49. /* Imported functions: */
  50.  
  51. void initialize_scanner (FILE *);
  52. int run_spim (mem_addr, register int, int);
  53. int yylex (void);
  54. int yyparse (void);
  55.  
  56. /* Internal functions: */
  57.  
  58. static void delete_all_breakpoints (void);
  59. static mem_addr copy_int_to_stack (int n);
  60. static mem_addr copy_str_to_stack (const char *s);
  61.  
  62.  
  63. /* Global Variables: */
  64.  
  65. int bare_machine = 0;        /* Non-zero => ignore assembler
  66.                    embellishments to bare hardware */
  67.  
  68. int quiet = 0;            /* Non-zero => no message on traps. */
  69.  
  70. extern char *input_file_name;        /* Name of file being parsed */
  71.  
  72. extern int yylval;        /* Value of token from YYLEX */
  73.  
  74. int message_out = 0, console_out = 0;
  75.  
  76. mem_addr program_starting_address = 0;
  77.  
  78. long initial_text_size = TEXT_SIZE;
  79.  
  80. long initial_data_size = DATA_SIZE;
  81.  
  82. long initial_data_limit = DATA_LIMIT;
  83.  
  84. long initial_stack_size = STACK_SIZE;
  85.  
  86. long initial_stack_limit = STACK_LIMIT;
  87.  
  88. long initial_k_text_size = K_TEXT_SIZE;
  89.  
  90. long initial_k_data_size = K_DATA_SIZE;
  91.  
  92. long initial_k_data_limit = K_DATA_LIMIT;
  93.  
  94.  
  95.  
  96. /* Initialize or reinitialize the state of the machine. */
  97.  
  98. void initialize_world (int load_trap_handler)
  99. {
  100.   /* Allocate the floating point registers */
  101.   if (FGR == NULL)
  102.     FPR = (double *) malloc (16 * sizeof (double));
  103.   /* Allocate the memory */
  104.   make_memory (initial_text_size,
  105.            initial_data_size, initial_data_limit,
  106.            initial_stack_size, initial_stack_limit,
  107.            initial_k_text_size,
  108.            initial_k_data_size, initial_k_data_limit);
  109.   initialize_registers ();
  110.   initialize_symbol_table ();
  111.   k_text_begins_at_point (K_TEXT_BOT);
  112.   k_data_begins_at_point (K_DATA_BOT);
  113.   data_begins_at_point (DATA_BOT);
  114.   text_begins_at_point (TEXT_BOT);
  115.   if (load_trap_handler)
  116.     {
  117.       int old_bare = bare_machine;
  118.  
  119.       bare_machine = 0;        /* Trap handler uses extended machine */
  120.       if (read_assembly_file (DEFAULT_TRAP_HANDLER))
  121.     fatal_error ("Cannot read trap handler\n");
  122.       bare_machine = old_bare;
  123.     }
  124.   initialize_scanner (stdin);
  125.   delete_all_breakpoints ();
  126.   program_starting_address = 0;
  127.   sprintf(mess_buff, "SPIM %s\n", SPIM_VERSION);
  128.   write_output (message_out, mess_buff);
  129. #ifndef MACINTOSH
  130.   /* the mac has a sexier way to present this information */
  131.   write_output (message_out,
  132.         "Copyright 1990-92 by James R. Larus (larus@cs.wisc.edu)\n");
  133.   write_output (message_out,
  134.     "Modified to read SAL code by Scott Kempf (scottk@cs.wis.edu)\n");
  135.   write_output (message_out, "See the file COPYING for license information\n");
  136. #endif
  137. }
  138.  
  139.  
  140.  
  141. void initialize_registers (void)
  142. {
  143.   bzero (FPR, 16 * sizeof (double));
  144.   FGR = (float *) FPR;
  145.   FWR = (int *) FPR;
  146.   bzero (R, 32 * sizeof (reg_word));
  147.   R[29] = STACK_TOP - BYTES_PER_WORD - 4096; /* Initialize $sp */
  148.   PC = 0;
  149.   Cause = 0;
  150.   EPC = 0;
  151.   Status_Reg = 0;
  152.   BadVAddr = 0;
  153.   Context = 0;
  154.   PRId = 0;
  155. }
  156.  
  157.  
  158. /* Read file NAME, which should contain assembly code. Return zero if
  159.    successful and non-zero otherwise. */
  160.  
  161. int read_assembly_file (char *name)
  162. {
  163.   FILE *file = fopen (name, "r");;
  164.  
  165.   source_file = 1;
  166.   if (file == NULL)
  167.     {
  168.       sprintf(mess_buff, "Cannot open file: `%s'\n", name);
  169.       error (mess_buff);
  170.       return (1);
  171.     }
  172.   else
  173.     {
  174. #ifdef mips
  175. #include <sys/exec.h>
  176.       unsigned short magic;
  177.  
  178.       fread (&magic, sizeof (short), 1, file);
  179.       fclose (file);
  180.       if (magic == MIPSEBMAGIC || magic == MIPSELMAGIC)
  181.     {
  182.       sprintf(mess_buff, "Source file appears to be executable: %s\n",
  183.             name);
  184.       error (mess_buff);
  185.       return (1);
  186.     }
  187.       fopen (name, "r");
  188. #endif
  189.       input_file_name = name;
  190.       initialize_scanner (file);
  191.       while (yyparse ()) ;
  192.       fclose (file);
  193.       flush_local_labels ();
  194.       return (0);
  195.     }
  196. }
  197.  
  198.  
  199. mem_addr starting_address (void)
  200. {
  201.   if (PC == 0)
  202.     {
  203.       if (program_starting_address)
  204.     return (program_starting_address);
  205.       else {
  206.     program_starting_address = find_symbol_address (DEFAULT_RUN_LOCATION);
  207.     if (program_starting_address == 0) {
  208.       sprintf(mess_buff, "Program starting label undefined (%s)\n",
  209.             DEFAULT_RUN_LOCATION);
  210.       error(mess_buff);
  211.           program_starting_address = TEXT_BOT;
  212.     }
  213.     return program_starting_address;
  214.       }
  215.     }
  216.   else
  217.     return (PC);
  218. }
  219.  
  220.  
  221. /* Initialize the SPIM stack with ARGC, ARGV, and ENVP data. */
  222.  
  223. void initialize_run_stack (int argc, const char **argv)
  224. {
  225.   char **p;
  226. #ifndef MACINTOSH
  227.   extern char **environ;
  228. #endif
  229.   int i, j = 0, env_j;
  230.   mem_addr addrs[10000];
  231.  
  232.   /* Put strings on stack: */
  233. #ifndef MACINTOSH
  234.   for (p = environ; *p != '\0'; p++)
  235.     addrs[j++] = copy_str_to_stack (*p);
  236. #endif
  237.  
  238.   R[REG_A1] = R[29];
  239.   env_j = j;
  240.   for (i = 0; i < argc; i++)
  241.     addrs[j++] = copy_str_to_stack (argv[i]);
  242.  
  243.   R[29] -= 4;            /* Leave rest of word empty */
  244.   R[29] = R[29] & 0xfffffff8;    /* Round down to double word boundary */
  245.   /* Build vectors on stack: */
  246.   for (i = env_j - 1; i >= 0; i--)
  247.     copy_int_to_stack (addrs[i]);
  248.   for (i = j - 1; i >= env_j; i--)
  249.     copy_int_to_stack (addrs[i]);
  250.  
  251.   R[29] = copy_int_to_stack (argc); /* Leave pointing to argc */
  252.   R[29] = R[29] & 0xfffffff8;    /* Round down to double word boundary */
  253. }
  254.  
  255.  
  256. static mem_addr copy_str_to_stack (const char *s)
  257. {
  258.   mem_addr str_start;
  259.   int i = strlen (s);
  260.  
  261.   while (i >= 0)
  262.     {
  263.       SET_MEM_BYTE (R[29], s[i]);
  264.       R[29] -= 1;
  265.       i -= 1;
  266.     }
  267.   str_start = (mem_addr) R[29] + 1;
  268.   R[29] = R[29] & 0xfffffff8;    /* Round down to double word boundary */
  269.   return (str_start);
  270. }
  271.  
  272.  
  273. static mem_addr copy_int_to_stack (int n)
  274. {
  275.   SET_MEM_WORD (R[29], n);
  276.   R[29] -= BYTES_PER_WORD;
  277.   return ((mem_addr) R[29] + BYTES_PER_WORD);
  278. }
  279.  
  280.  
  281. /* Run a program starting at PC for N steps and display each
  282.    instruction before executing if FLAG is non-zero.  If CONTINUE is
  283.    non-zero, then step through a breakpoint.  Return non-zero if
  284.    breakpoint is encountered. */
  285.  
  286. int run_program (mem_addr pc, int steps, int display, int cont_bkpt)
  287. {
  288.   if (cont_bkpt && inst_is_breakpoint (pc))
  289.     {
  290.       mem_addr addr = PC;
  291.  
  292.       delete_breakpoint (addr);
  293.       exception_occurred = 0;
  294.       run_spim (addr, 1, display);
  295.       add_breakpoint (addr);
  296.       steps -= 1;
  297.       pc = PC;
  298.     }
  299.  
  300.   exception_occurred = 0;
  301.   if (!run_spim (pc, steps, display))
  302.     /* Can't restart program */
  303.     PC = 0;
  304.   if (exception_occurred && Cause == (BKPT_EXCPT << 2))
  305.     return (1);
  306.   else
  307.     return (0);
  308. }
  309.  
  310.  
  311. /* Record of where a breakpoint was placed and the instruction previously
  312.    in memory. */
  313.  
  314. typedef struct bkptrec
  315. {
  316.   mem_addr addr;
  317.   instruction *inst;
  318.   struct bkptrec *next;
  319. } bkpt;
  320.  
  321.  
  322. static bkpt *bkpts = NULL;
  323.  
  324.  
  325. /* Set a breakpoint at memory location ADDR. */
  326.  
  327. void add_breakpoint (mem_addr addr)
  328. {
  329.   bkpt *rec = (bkpt *) malloc (sizeof (bkpt));
  330.  
  331.   rec->next = bkpts;
  332.   rec->addr = addr;
  333.  
  334.   if ((rec->inst = set_breakpoint (addr)) != NULL)
  335.     bkpts = rec;
  336.   else
  337.     {
  338.       if (exception_occurred) {
  339.     sprintf(mess_buff, "Cannot put a breakpoint at address 0x%08x\n",
  340.           addr);
  341.     error (mess_buff);
  342.       }
  343.       else {
  344.     sprintf(mess_buff, "Already have a breakpoint at address 0x%08x\n",
  345.           addr);
  346.     error (mess_buff);
  347.       }
  348.       free (rec);
  349.     }
  350. }
  351.  
  352.  
  353. /* Delete all breakpoints at memory location ADDR. */
  354.  
  355. void delete_breakpoint (mem_addr addr)
  356. {
  357.   bkpt *p, *b;
  358.   int deleted_one = 0;
  359.  
  360.   for (p = NULL, b = bkpts; b != NULL; )
  361.     if (b->addr == addr)
  362.       {
  363.     bkpt *n;
  364.  
  365.     SET_MEM_INST (addr, b->inst);
  366.     if (p == NULL)
  367.       bkpts = b->next;
  368.     else
  369.       p->next = b->next;
  370.     n = b->next;
  371.     free (b);
  372.     b = n;
  373.     deleted_one = 1;
  374.       }
  375.     else
  376.       p = b, b = b->next;
  377.   if (!deleted_one) {
  378.     sprintf(mess_buff, "No breakpoint to delete at 0x%08x\n", addr);
  379.     error (mess_buff);
  380.   }
  381. }
  382.  
  383.  
  384. static void delete_all_breakpoints (void)
  385. {
  386.   bkpt *b, *n;
  387.  
  388.   for (b = bkpts, n = NULL; b != NULL; b = n)
  389.     {
  390.       n = b->next;
  391.       free (b);
  392.     }
  393.   bkpts = NULL;
  394. }
  395.  
  396.  
  397. /* List all breakpoints. */
  398.  
  399. void list_breakpoints (void)
  400. {
  401.   bkpt *b;
  402.  
  403.   if (bkpts) {
  404.     for (b = bkpts;  b != NULL; b = b->next) {
  405.       sprintf(mess_buff, "Breakpoint at 0x%08x\n", b->addr);
  406.       write_output (message_out, mess_buff);
  407.     }
  408.   }
  409.   else {
  410.     write_output (message_out, "No breakpoints set\n");
  411.   }
  412. }
  413.  
  414.  
  415.  
  416. /* Utility routines */
  417.  
  418. /* Print the error message then exit. */
  419.  
  420. void fatal_error (char *string)
  421. {
  422. #ifdef MACINTOSH
  423.   MacFatalError(string);
  424. #else
  425.   fprintf (stderr, "%s", string);
  426.   exit (-1);
  427.   /*NOTREACHED*/
  428. #endif
  429. }
  430.  
  431.  
  432. /* Return the entry in the hash TABLE of length LENGTH with key STRING.
  433.    Return NULL if no such entry exists. */
  434.  
  435. inst_info * map_string_to_inst_info (register inst_info tbl[], int tbl_len, 
  436.     register char *id)
  437. {
  438.   register int low = 0;
  439.   register int hi = tbl_len - 1;
  440.  
  441.   while (low <= hi)
  442.     {
  443.       register int mid = (low + hi) / 2;
  444.       register char *idp = id, *np = tbl[mid].name;
  445.  
  446.       while (*idp == *np && *idp != '\0') {idp ++; np ++;}
  447.  
  448.       if (*np == '\0' && *idp == '\0') /* End of both strings */
  449.     return (& tbl[mid]);
  450.       else if (*idp > *np)
  451.     low = mid + 1;
  452.       else
  453.     hi = mid - 1;
  454.     }
  455.  
  456.   return NULL;
  457. }
  458.  
  459.  
  460. /* Return the entry in the hash TABLE of length LENGTH with VALUE1 field NUM.
  461.    Return NULL if no such entry exists. */
  462.  
  463. inst_info *map_int_to_inst_info (register inst_info tbl[], int tbl_len, 
  464.     register int num)
  465. {
  466.   register int low = 0;
  467.   register int hi = tbl_len - 1;
  468.  
  469.   while (low <= hi)
  470.     {
  471.       register int mid = (low + hi) / 2;
  472.  
  473.       if (tbl[mid].value1 == num)
  474.     return (&tbl[mid]);
  475.       else if (num > tbl[mid].value1)
  476.     low = mid + 1;
  477.       else
  478.     hi = mid - 1;
  479.     }
  480.  
  481.   return NULL;
  482. }
  483.  
  484.  
  485. #ifdef NEED_STRTOL
  486. long strtol (char *str, char *eptr, int base)
  487. {
  488.   long result;
  489.  
  490.   if (base != 16)
  491.     fatal_error ("SPIM's strtol only works for base 16");
  492.   if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X'))
  493.     str += 2;
  494.   sscanf (str, "%lx", &result);
  495.   return (result);
  496. }
  497. #endif
  498.